package com.bee.shepherd.common.aop;

import com.alibaba.dubbo.registry.support.QunarApp;
import com.google.common.base.Joiner;
import com.qunar.flight.qmonitor.QMonitor;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.MessageFormat;

/**
 * redis key统一增加应用前缀
 * (demo: beta_appcode)
 */
@Aspect
@Component
public class RedisPrefixKeyGenAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(RedisPrefixKeyGenAspect.class);

    private static Joiner JOINER = Joiner.on("_").skipNulls();

    @Pointcut("@within(com.bee.shepherd.common.aop.RedisPrefixKeyGen)")
    public void genKeyPrefixAspect() {
    }

    @Around("genKeyPrefixAspect()")
    public Object genKey(ProceedingJoinPoint joinPoint) throws Throwable {
        // 只拦截public方法
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        String methodName = method.getName();
        QMonitor.recordOne("process_call_redis");
        QMonitor.recordOne("process_call_redis_method_"+methodName);
        LOGGER.info("process_call_redis method:{}",methodName);

        if (!isPublicMethod(method)) {
            return joinPoint.proceed();
        }
        // 参数校验，第一个参数必须为不为空的字符串key
        Object[] paramArgs = joinPoint.getArgs();
        if (ArrayUtils.isEmpty(paramArgs)) {
            String errorMsg = MessageFormat.format("redis参数不能为空 methodName:{0}", methodName);
            throw new RuntimeException(errorMsg);
        }
        Object keyObjValue = paramArgs[0];
        if (keyObjValue == null) {
            String errorMsg = MessageFormat.format("redis key不能为null methodName:{0}", methodName);
            throw new RuntimeException(errorMsg);
        }
        if (!(keyObjValue instanceof String)) {
            String errorMsg = MessageFormat.format("redis key必须为字符串格式 methodName:{0} key:{1}", methodName, keyObjValue);
            throw new RuntimeException(errorMsg);
        }
        String key = (String) keyObjValue;
        if (StringUtils.isBlank(key)) {
            String errorMsg = MessageFormat.format("redis key不能为空 methodName:{0}", methodName);
            throw new RuntimeException(errorMsg);
        }
        // key前面增加应用前缀
        String newKey = createKeyWithPrefix(key);
        // 替换方法参数、执行方法
        paramArgs[0] = newKey;
        return joinPoint.proceed(paramArgs);
    }
    /**
     * 校验当前方法是否为public方法
     */
    private boolean isPublicMethod(Method method) {
        return Modifier.isPublic(method.getModifiers());
    }

    /**
     * key前面增加应用前缀 appType、appName，
     * 如:beta_appcode
     */
    private String createKeyWithPrefix(String key) {
        //环境
        String appType = QunarApp.INSTANCE.getType().name();
        //appcode
        String appName = QunarApp.INSTANCE.getName();
        return JOINER.join(appType, appName, key);
    }
}
